home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 22
/
Cream of the Crop 22.iso
/
program
/
tdk_v120.zip
/
ASYNC.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-07-15
|
61KB
|
1,197 lines
{
▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀ ▀▀ ▀▀
▀▀ ▀▀ ▀▀ ▀▀ ▀▀
▀▀ ▀▀ ▀▀▀ ▀▀▀▀▀ The DoorKit!
▀▀ ▀▀ ▀▀ ▀▀ ▀▀
▀▀ ▀▀▀▀▀▀ ▀▀ ▀▀
The BBS Door Development Kit By The People - For The People!
Feel free to modify or optimize this code at will. All I ask is that if
find a better way to do things (and you will), please send me a copy of
your modifications. Thanks in advance!....Larry L. Athey....}
{*--------------------------------------------------------------------------*}
{* *}
{* Status byte definition (C_Status): *}
{* *}
{* 7 6 5 4 3 2 1 0 *}
{* | | | | | | | |____ Input buffer empty *}
{* | | | | | | |________ Input buffer full *}
{* | | | | | |____________ Output buffer empty *}
{* | | | | |________________ Output buffer full *}
{* | | | |____________________ Input buffer overflow *}
{* | | |________________________ Output buffer overflow *}
{* | |____________________________ Hard handshake active (xmit stopped) *}
{* |________________________________ Soft handshake active (xmit stopped) *}
{* *}
{* Control byte definition (C_Ctrl): *}
{* *}
{* 7 6 5 4 3 2 1 0 *}
{* | | | | | | | |____ Enable RTS handshake *}
{* | | | | | | |________ Enable CTS handshake *}
{* | | | | | |____________ Enable software handshake *}
{* | | | | |________________ *}
{* | | | |____________________ *}
{* | | |________________________ *}
{* | |____________________________ *}
{* |________________________________ *}
{* *}
{****************************************************************************}
{$R-,V-,B-,S-}
Unit ASYNC;
INTERFACE
{----------------------------------------------------------------------------}
CONST
C_MinBaud = 300;
C_MaxBaud = 115200;
C_MaxPort = 4;
C_MaxCom : BYTE = C_MaxPort;
C_PortAddr : ARRAY[1..C_MaxPort] OF WORD = ($03F8,$02F8,$03E8,$02E8);
C_PortInt : ARRAY[1..C_MaxPort] OF BYTE = (4,3,4,3);
{----------------------------------------------------------------------------}
TYPE
C_VectorArray = ARRAY[0..15] OF POINTER;
C_PointerArray = ARRAY[1..C_MaxPort] OF POINTER;
C_WordArray = ARRAY[1..C_MaxPort] OF WORD;
C_ByteArray = ARRAY[1..C_MaxPort] OF BYTE;
C_CharArray = ARRAY[1..C_MaxPort] OF CHAR;
C_BooleanArray = ARRAY[1..C_MaxPort] OF BOOLEAN;
{----------------------------------------------------------------------------}
VAR
{ Base port addresses & interrupt usage }
{ C_PortAddr : Array[1..C_MaxPort] Of Word;
C_PortInt : Array[1..C_MaxPort] Of Byte;{}
ComPort : BYTE;
C_InBufPtr,C_OutBufPtr : C_PointerArray; { Input/output buffer pointers }
C_InHead,C_OutHead : C_WordArray; { Input/output head pointers }
C_InTail,C_OutTail : C_WordArray; { Input/output tail pointers }
C_InSize,C_OutSize : C_WordArray; { Input/output buffer sizes }
C_RTSOn,C_RTSOff : C_WordArray; { RTS assert/drop buffer points }
C_StartChar,C_StopChar : C_CharArray; { Soft hndshake start/stop char }
C_Status,C_Ctrl : C_ByteArray; { STATUS and CONTROL registers }
C_XL3Ptr : C_ByteArray;
C_PortOpen : C_BooleanArray; { Port open/close flags }
C_Temp : WORD; { Used for debugging }
C_msrport : WORD;
{ RTSOn,RTSOff : Word; { RTS assert/drop buffer points }
{ oldier,oldmcr : byte;}
c_oldier,c_oldmcr : c_bytearray;
c_oldfcr : c_bytearray; { old FIFO status}
c_fifoOK : c_booleanarray;
c_buffull : c_wordarray;
{ C_Cascade : Byte; { Flag set 0 normally }
{ C_CascadeOK : boolean; { Flag if IRQ > 7 }
C_Cascade : c_Bytearray; { Flag set 0 normally }
C_CascadeOK : c_booleanarray; { Flag if IRQ > 7 }
{----------------------------------------------------------------------------}
FUNCTION ComReadCh(ComPort : BYTE) : CHAR;
FUNCTION ComReadChW(ComPort : BYTE) : CHAR;
{ Procedure ComWriteCh(ComPort:Byte; Ch:Char); }
PROCEDURE ComWriteChW(ComPort : BYTE; Ch : CHAR);
PROCEDURE SetDTR(ComPort : BYTE; Assert : BOOLEAN);
PROCEDURE SetRTS(ComPort : BYTE; Assert : BOOLEAN);
{ Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
Procedure SetOUT2(ComPort:Byte; Assert:Boolean);}
FUNCTION CTSStat(ComPort : BYTE) : BOOLEAN;
FUNCTION RTSStat(ComPort : BYTE) : BOOLEAN;
FUNCTION DSRStat(ComPort : BYTE) : BOOLEAN;
FUNCTION RIStat(ComPort : BYTE) : BOOLEAN;
FUNCTION DCDStat(ComPort : BYTE) : BOOLEAN;
PROCEDURE SetRTSMode(ComPort : BYTE; Mode : BOOLEAN; RTSOn,RTSOff : WORD);
PROCEDURE SetCTSMode(ComPort : BYTE; Mode : BOOLEAN);
PROCEDURE SoftHandshake(ComPort : BYTE; Mode : BOOLEAN; Start,Stop : CHAR);
PROCEDURE ClearCom(ComPort : BYTE; IO : CHAR);
FUNCTION ComBufferLeft(ComPort : BYTE; IO : CHAR) : WORD;
PROCEDURE ComWaitForClear(ComPort : BYTE);
PROCEDURE I_ComWrite(ComPort : BYTE; St : STRING);
PROCEDURE I_ComWriteln(ComPort : BYTE; St : STRING);
PROCEDURE I_ComWriteWithDelay(ComPort : BYTE; St : STRING; Dly : WORD);
PROCEDURE I_ComReadln(ComPort : BYTE; VAR St : STRING; Size : BYTE; Echo : BOOLEAN);
FUNCTION ComExist(ComPort : BYTE) : BOOLEAN;
FUNCTION ComTrueBaud(Baud : LONGINT) : REAL;
PROCEDURE ComParams(ComPort : BYTE; Baud : LONGINT; WordSize : BYTE; Parity : CHAR; StopBits : BYTE);
FUNCTION OpenCom(ComPort : BYTE; InBufferSize,OutBufferSize : WORD) : BOOLEAN;
PROCEDURE CloseCom(ComPort : BYTE);
PROCEDURE CloseAllComs;
{----------------------------------------------------------------------------}
IMPLEMENTATION
Uses DOS,CRT;
{$L ASYNC.OBJ}
CONST
C_IER = 1; { 8250 register offsets }
C_IIR = 2;
C_LCR = 3;
C_MCR = 4;
C_LSR = 5;
C_MSR = 6;
C_SCR = 7;
VAR
C_OldINTVec : C_VectorArray; { Storage for old hardware INT vectors }
X : BYTE; { Used by initialization code }
{****************************************************************************}
{* *}
{* Procedure INT_Handler; External; *}
{* *}
{* Hardware interrupts 0-15 (vectors $08 - $0F,$70 - $77) are pointed to *}
{* this routine. It is for internal use only and should NOT be called *}
{* directly. Written in assembly language (see ASYNC.ASM). *}
{* *}
{****************************************************************************}
PROCEDURE INT_Handler; EXTERNAL;
{****************************************************************************}
{* *}
{* Procedure ComReadCh(ComPort:Byte) : Char; External; *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* *}
{* Returns character from input buffer of specified port. If the buffer *}
{* is empty, the port # invalid or not opened, a Chr(0) is returned. *}
{* Written in assembly language for best possible speed (see ASYNC.ASM) *}
{* *}
{****************************************************************************}
FUNCTION ComReadCh(ComPort : BYTE) : CHAR; EXTERNAL;
{****************************************************************************}
{* *}
{* Function ComReadChW(ComPort:Byte) : Char; External; *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* *}
{* Works like ComReadCh, but will wait until at least 1 character is *}
{* present in the specified input buffer before exiting. Thus, ComReadChW *}
{* works much like the ReadKey predefined function. Written in assembly *}
{* language to maximize performance (see ASYNC.ASM) *}
{* *}
{****************************************************************************}
FUNCTION ComReadChW(ComPort : BYTE) : CHAR; EXTERNAL;
{****************************************************************************}
{* *}
{* Procedure ComWriteCh(ComPort:Byte; Ch:Char); External *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Ch:Char -> Character to send *}
{* *}
{* Places the character [Ch] in the transmit buffer of the specified port. *}
{* If the port specified is not open or nonexistent, or if the buffer is *}
{* filled, the character is discarded. Written in assembly language to *}
{* maximize performance (see ASYNC.ASM) *}
{* *}
{****************************************************************************}
PROCEDURE ComWriteCh(ComPort : BYTE; Ch : CHAR); EXTERNAL;
{****************************************************************************}
{* *}
{* Procedure ComWriteChW(ComPort:Byte; Ch:Char); External; *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Ch:Char -> Character to send *}
{* *}
{* Works as ComWriteCh, but will wait until at least 1 free position is *}
{* available in the output buffer before attempting to place the character *}
{* [Ch] in it. Allows the programmer to send characters without regard to *}
{* available buffer space. Written in assembly language to maximize *}
{* performance (see ASYNC.ASM) *}
{* *}
{****************************************************************************}
PROCEDURE ComWriteChW(ComPort : BYTE; Ch : CHAR); EXTERNAL;
{****************************************************************************}
{* *}
{* Procedure SetDTR(ComPort:Byte; Assert:Boolean); *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Call ignored if out-of-range *}
{* Assert:Boolean -> DTR assertion flag (TRUE to assert DTR) *}
{* *}
{* Provides a means to control the port's DTR (Data Terminal Ready) signal *}
{* line. When [Assert] is TRUE, the DTR line is placed in the "active" *}
{* state, signalling to a remote system that the host is "on-line" *}
{* (although not nessesarily ready to receive data - see SetRTS). *}
{* *}
{****************************************************************************}
PROCEDURE SetDTR(ComPort : BYTE; Assert : BOOLEAN);
VAR
P,X : INTEGER;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN EXIT;
P := C_PortAddr[ComPort];
X := Port[P + C_MCR];
IF Assert THEN
X := X OR $01
ELSE
X := X AND $FE;
Port[P + C_MCR] := X;
END;
{****************************************************************************}
{* *}
{* Procedure SetRTS(ComPort:Byte; Assert:Boolean) *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Call ignored if out-of-range *}
{* Assert:Boolean -> RTS assertion flag (Set TRUE to assert RTS) *}
{* *}
{* SetRTS allows a program to manually control the Request-To-Send (RTS) *}
{* signal line. If RTS handshaking is disabled (see C_Ctrl definition *}
{* and the the SetRTSMode procedure), this procedure may be used. SetRTS *}
{* should NOT be used if RTS handshaking is enabled. *}
{* *}
{****************************************************************************}
PROCEDURE SetRTS(ComPort : BYTE; Assert : BOOLEAN);
VAR
P,X : INTEGER;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN EXIT;
P := C_PortAddr[ComPort];
X := Port[P + C_MCR];
IF Assert THEN
X := X OR $02
ELSE
X := X AND $FD;
Port[P + C_MCR] := X;
END;
{****************************************************************************}
{* *}
{* Procedure SetOUT1(ComPort:Byte; Assert:Boolean) *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Call ignored if out-of-range *}
{* Assert:Boolean -> OUT1 assertion flag (set TRUE to assert OUT1 line) *}
{* *}
{* SetOUT1 is provided for reasons of completeness only, since the *}
{* standard PC/XT/AT configurations do not utilize this control signal. *}
{* If [Assert] is TRUE, the OUT1 signal line on the 8250 will be set to a *}
{* LOW logic level (inverted logic). The OUT1 signal is present on pin 34 *}
{* of the 8250 (but not on the port itself). *}
{* *}
{****************************************************************************}
{
Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
Var
P,X : Integer;
Begin
If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
P := C_PortAddr[ComPort];
X := Port[P+C_MCR];
If Assert Then
X := X Or $04
Else
X := X And $FB;
Port[P+C_MCR] := X;
End;
}
{****************************************************************************}
{* *}
{* Procedure SetOUT2(ComPort:Byte; Assert:Boolean) *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Call ignored if out-of-range *}
{* Assert:Boolean -> OUT2 assertion flag (set TRUE to assert OUT2 line) *}
{* *}
{* The OUT2 signal line, although not available on the port itself, is *}
{* used to gate the 8250 <INTRPT> (interrupt) line and thus acts as a *}
{* redundant means of controlling 8250 interrupts. When [Assert] is TRUE, *}
{* the /OUT2 line on the 8250 is lowered, which allows the passage of the *}
{* <INTRPT> signal through a gating arrangement, allowing the 8250 to *}
{* generate interrupts. Int's can be disabled bu unASSERTing this line. *}
{* *}
{****************************************************************************}
{
Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
Var
P,X : Integer;
Begin
If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
P := C_PortAddr[ComPort];
X := Port[P+C_MCR];
If Assert Then
X := X Or $08
Else
X := X And $F7;
Port[P+C_MCR] := X;
End;
}
{****************************************************************************}
{* *}
{* Function CTSStat(ComPort:Byte) : Boolean *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Call ignored if out-of-range *}
{* Returns status of Clear-To-Send line (TRUE if CTS asserted) *}
{* *}
{* CTSStat provides a means to interrogate the Clear-To-Send hardware *}
{* handshaking line. In a typical arrangement, when CTS is asserted, this *}
{* signals the host (this computer) that the receiver is ready to accept *}
{* data (in contrast to the DSR line, which signals the receiver as *}
{* on-line but not nessesarily ready to accept data). An automated mech- *}
{* ansim (see CTSMode) is provided to do this, but in cases where this is *}
{* undesirable or inappropriate, the CTSStat function can be used to int- *}
{* terrogate this line manually. *}
{* *}
{****************************************************************************}
FUNCTION CTSStat(ComPort : BYTE) : BOOLEAN;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
CTSStat := FALSE
ELSE
CTSStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $10 <> $10);
END;
{****************************************************************************}
{* *}
{* Function RTSStat(ComPort:Byte) : Boolean *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Call ignored if out-of-range *}
{* Returns status of Ready-To-Send line (TRUE if RTS asserted) *}
{* *}
{****************************************************************************}
FUNCTION RTSStat(ComPort : BYTE) : BOOLEAN;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
RTSStat := FALSE
ELSE
RTSStat := (Port[C_PortAddr[ComPort] + C_LSR] AND $20 <> $20);
END;
{****************************************************************************}
{* *}
{* Function DSRStat(ComPort:Byte) : Boolean *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Call ignored if out-of-range *}
{* Returns status of Data Set Ready (DSR) signal line. *}
{* *}
{* The Data Set Ready (DSR) line is typically used by a remote station *}
{* to signal the host system that it is on-line (although not nessesarily *}
{* ready to receive data yet - see CTSStat). A remote station has the DSR *}
{* line asserted if DSRStat returns TRUE. *}
{* *}
{****************************************************************************}
FUNCTION DSRStat(ComPort : BYTE) : BOOLEAN;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
DSRStat := FALSE
ELSE
DSRStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $20) > 0;
END;
{****************************************************************************}
{* *}
{* Function RIStat(ComPort:Byte) : Boolean *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Call ignored if out-of-range *}
{* *}
{* Returns the status of the Ring Indicator (RI) line. This line is *}
{* typically used only by modems, and indicates that the modem has detect- *}
{* ed an incoming call if RIStat returns TRUE. *}
{* *}
{****************************************************************************}
FUNCTION RIStat(ComPort : BYTE) : BOOLEAN;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
RIStat := FALSE
ELSE
RIStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $40) > 0;
END;
{****************************************************************************}
{* *}
{* Function DCDStat(ComPort:Byte) : Boolean *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Call ignored if out-of-range *}
{* *}
{* Returns the status of the Data Carrier Detect (DCD) line from the rem- *}
{* ote device, typically a modem. When asserted (DCDStat returns TRUE), *}
{* the modem indicates that it has successfuly linked with another modem *}
{* device at another site. *}
{* *}
{****************************************************************************}
FUNCTION DCDStat(ComPort : BYTE) : BOOLEAN;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
DCDStat := FALSE
ELSE
DCDStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $80) > 0;
END;
{****************************************************************************}
{* *}
{* Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word) *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Request ignored if out of range or unopened. *}
{* Mode:Boolean -> TRUE to enable automatic RTS handshake *}
{* RTSOn:Word -> Buffer-usage point at which the RTS line is asserted *}
{* RTSOff:Word -> Buffer-usage point at which the RTS line is dropped *}
{* *}
{* SetRTSMode enables or disables automated RTS handshaking. If [MODE] is *}
{* TRUE, automated RTS handshaking is enabled. If enabled, the RTS line *}
{* will be DROPPED when the # of buffer bytes used reaches or exceeds that *}
{* of [RTSOff]. The RTS line will then be re-asserted when the buffer is *}
{* emptied down to the [RTSOn] usage point. If either [RTSOn] or [RTSOff] *}
{* exceeds the input buffer size, they will be forced to (buffersize-1). *}
{* If [RTSOn] > [RTSOff] then [RTSOn] will be the same as [RTSOff]. *}
{* The actual handshaking control is located in the interrupt driver for *}
{* the port (see ASYNC.ASM). *}
{* *}
{****************************************************************************}
PROCEDURE SetRTSMode(ComPort : BYTE; Mode : BOOLEAN; RTSOn,RTSOff : WORD);
VAR
X : BYTE;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
X := C_Ctrl[ComPort];
IF Mode THEN X := X OR $01 ELSE X := X AND $FE;
C_Ctrl[ComPort] := X;
IF Mode THEN
BEGIN
IF (RTSOff >= C_InSize[ComPort]) THEN RTSOff := C_InSize[ComPort] - 1;
IF (RTSOn > RTSOff) THEN RTSOff := RTSOn;
C_RTSOn[ComPort] := RTSOn;
C_RTSOff[ComPort] := RTSOff;
END;
END;
{****************************************************************************}
{* *}
{* Procedure SetCTSMode(ComPort:Byte; Mode:Boolean) *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Request ignored if out of range or unopened. *}
{* Mode:Boolean -> Set to TRUE to enable automatic CTS handshake. *}
{* *}
{* SetCTSMode allows the enabling or disabling of automated CTS handshak- *}
{* ing. If [Mode] is TRUE, CTS handshaking is enabled, which means that *}
{* if the remote drops the CTS line, the transmitter will be disabled *}
{* until the CTS line is asserted again. Automatic handshake is disabled *}
{* if [Mode] is FALSE. CTS handshaking and "software" handshaking (pro- *}
{* vided by the SoftHandshake procedure) ARE compatable and may be used *}
{* in any combination. The actual logic for CTS handshaking is located *}
{* in the communications interrupt driver (see ASYNC.ASM). *}
{* *}
{****************************************************************************}
PROCEDURE SetCTSMode(ComPort : BYTE; Mode : BOOLEAN);
VAR
X : BYTE;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
X := C_Ctrl[ComPort];
IF Mode THEN X := X OR $02 ELSE X := X AND $FD;
C_Ctrl[ComPort] := X;
END;
{****************************************************************************}
{* *}
{* Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char) *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Request ignored if out of range or unopened. *}
{* Mode:Boolean -> Set to TRUE to enable transmit software handshake *}
{* Start:Char -> START control character (usually ^Q) *}
{* Defaults to ^Q if character passed is >= <Space> *}
{* Stop:Char -> STOP control character (usually ^S) *}
{* Defaults to ^S if character passed is >= <Space> *}
{* *}
{* SoftHandshake controls the usage of "Software" (control-character) *}
{* handshaking on transmission. If "software handshake" is enabled *}
{* ([Mode] is TRUE), transmission will be halted if the character in *}
{* [Stop] is received. Transmission is re-enabled if the [Start] char- *}
{* acter is received. Both the [Start] and [Stop] characters MUST be *}
{* CONTROL characters (i.e. Ord(Start) and Ord(Stop) must both be < 32). *}
{* Also, <Start> and <Stop> CANNOT be the same character. If either one *}
{* of these restrictions are violated, the defaults (^Q for <Start> and ^S *}
{* for <Stop>) will be used. Software handshaking control is implimented *}
{* within the communications interrupt driver (see ASYNC.ASM). *}
{* *}
{****************************************************************************}
PROCEDURE SoftHandshake(ComPort : BYTE; Mode : BOOLEAN; Start,Stop : CHAR);
VAR
X : BYTE;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
X := C_Ctrl[ComPort];
IF Mode THEN
BEGIN
X := X OR $04;
IF Start = Stop THEN BEGIN Start := ^Q; Stop := ^S; END;
IF Start > #32 THEN Start := ^Q;
IF Stop > #32 THEN Stop := ^S;
C_StartChar[ComPort] := Start;
C_StopChar[ComPort] := Stop;
END
ELSE
X := X AND $FB;
C_Ctrl[ComPort] := X;
END;
{****************************************************************************}
{* *}
{* Procedure ClearCom(ComPort:Byte); IO:Char) *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Request ignored if out of range or unopened. *}
{* IO:Char -> Action code; I=Input, O=Output, B=Both *}
{* No action taken if action code unrecognized. *}
{* *}
{* ClearCom allows the user to completely clear the contents of either *}
{* the input (receive) and/or output (transmit) buffers. The "action *}
{* code" passed in <IO> determines if the input (I) or output (O) buffer *}
{* is cleared. Action code (B) will clear both buffers. This is useful *}
{* if you wish to cancel a transmitted message or ignore part of a *}
{* received message. *}
{* *}
{****************************************************************************}
PROCEDURE ClearCom(ComPort : BYTE; IO : CHAR);
VAR
P,X : WORD;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
IO := UPCASE(IO);
P := C_PortAddr[ComPort];
INLINE($FA);
IF (IO = 'I') OR (IO = 'B') THEN
BEGIN
C_InHead[ComPort] := 0;
C_InTail[ComPort] := 0;
C_Status[ComPort] := (C_Status[ComPort] AND $EC) OR $01;
X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
END;
IF (IO = 'O') OR (IO = 'B') THEN
BEGIN
C_OutHead[ComPort] := 0;
C_OutTail[ComPort] := 0;
C_Status[ComPort] := (C_Status[ComPort] AND $D3) OR $04;
X := Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
END;
INLINE($FB);
END;
{****************************************************************************}
{* *}
{* Procedure ComBufferLeft(ComPort:Byte; IO:Char) : Word *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Returns 0 if Port # invalid or unopened. *}
{* IO:Char -> Action code; I=Input, O=Output *}
{* Returns 0 if action code unrecognized. *}
{* *}
{* ComBufferLeft will return a number (bytes) indicating how much space *}
{* remains in the selected buffer. The INPUT buffer is checked if <IO> is *}
{* (I), and the output buffer is interrogated when <IO> is (O). Any other *}
{* "action code" will return a result of 0. Use this function when it is *}
{* important to avoid program delays due to calls to output procedures or *}
{* to prioritize the reception of data (to prevent overflows). *}
{* *}
{****************************************************************************}
FUNCTION ComBufferLeft(ComPort : BYTE; IO : CHAR) : WORD;
BEGIN
ComBufferLeft := 0;
IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
IO := UPCASE(IO);
IF IO = 'I' THEN
IF C_InHead[ComPort] >= C_InTail[ComPort] THEN
ComBufferLeft := C_InSize[ComPort] - (C_InHead[ComPort] - C_InTail[ComPort])
ELSE
ComBufferLeft := C_InTail[ComPort] - C_InHead[ComPort];
IF IO = 'O' THEN
IF C_OutHead[ComPort] >= C_OutTail[ComPort] THEN
ComBufferLeft := C_OutHead[ComPort] - C_OutTail[ComPort]
ELSE
ComBufferLeft := C_OutSize[ComPort] - (C_OutTail[ComPort] - C_OutHead[ComPort]);
END;
{****************************************************************************}
{* *}
{* Procedure ComWaitForClear(ComPort:Byte) *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Exits immediately if out of range or port unopened. *}
{* *}
{* A call to ComWaitForClear will stop processing until the selected out- *}
{* put buffer is completely emptied. Typically used just before a call *}
{* to the CloseCom procedure to prevent premature cut-off of messages in *}
{* transit. *}
{* *}
{****************************************************************************}
PROCEDURE ComWaitForClear(ComPort : BYTE);
VAR
Empty : BOOLEAN;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
REPEAT
Empty := (C_Status[ComPort] AND $04) = $04;
Empty := Empty AND ((Port[C_PortAddr[ComPort] + C_IER] AND $02) = $00);
UNTIL Empty;
END;
{****************************************************************************}
{* *}
{* Procedure ComWrite(ComPort:Byte; St:String) *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Exits immediately if out of range or port unopened. *}
{* St:String -> String to send *}
{* *}
{* Sends string <St> out communications port <ComPort>. *}
{* *}
{****************************************************************************}
PROCEDURE I_ComWrite(ComPort : BYTE; St : STRING);
VAR
X : BYTE;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
FOR X := 1 TO LENGTH(St) DO ComWriteChW(ComPort,St[X]);
END;
{****************************************************************************}
{* *}
{* Procedure ComWriteln(ComPort:Byte; St:String); *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Exits immediately if out of range or port unopened. *}
{* St:String -> String to send *}
{* *}
{* Sends string <St> with a CR and LF appended. *}
{* *}
{****************************************************************************}
PROCEDURE I_ComWriteln(ComPort : BYTE; St : STRING);
VAR
X : BYTE;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
FOR X := 1 TO LENGTH(St) DO ComWriteChW(ComPort,St[X]);
ComWriteChW(ComPort,#13);
ComWriteChW(ComPort,#10);
END;
{****************************************************************************}
{* *}
{* Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word); *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Exits immediately if out of range or port unopened. *}
{* St:String -> String to send *}
{* Dly:Word -> Time, in milliseconds, to delay between each char. *}
{* *}
{* ComWriteWithDelay will send string <St> to port <ComPort>, delaying *}
{* for <Dly> milliseconds between each character. Useful for systems that *}
{* cannot keep up with transmissions sent at full speed. *}
{* *}
{****************************************************************************}
PROCEDURE I_ComWriteWithDelay(ComPort : BYTE; St : STRING; Dly : WORD);
VAR
X : BYTE;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
ComWaitForClear(ComPort);
FOR X := 1 TO LENGTH(St) DO BEGIN
ComWriteChW(ComPort,St[X]);
ComWaitForClear(ComPort);
DELAY(Dly);
END;
END;
{****************************************************************************}
{* *}
{* Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean)*}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom). *}
{* Exits immediately if out of range or port unopened. *}
{* St:String <- Edited string from remote *}
{* Size:Byte; -> Maximum allowable length of input *}
{* Echo:Boolean; -> Set TRUE to echo received characters *}
{* *}
{* ComReadln is the remote equivalent of the standard Pascal READLN pro- *}
{* cedure with some enhancements. ComReadln will accept an entry of up to *}
{* 40 printable ASCII characters, supporting ^H and ^X editing commands. *}
{* Echo-back of the entry (for full-duplex operation) is optional. All *}
{* control characters, as well as non-ASCII (8th bit set) characters are *}
{* stripped. If <Echo> is enabled, ASCII BEL (^G) characters are sent *}
{* when erroneous characters are intercepted. Upon receipt of a ^M (CR), *}
{* the procedure is terminated and the final string result returned. *}
{* *}
{****************************************************************************}
PROCEDURE I_ComReadln(ComPort : BYTE; VAR St : STRING; Size : BYTE; Echo : BOOLEAN);
VAR
Len,X : BYTE;
Ch : CHAR;
Done : BOOLEAN;
BEGIN
St := '';
IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
Done := FALSE;
REPEAT
Len := LENGTH(St);
Ch := CHR(ORD(ComReadChW(ComPort)) AND $7F);
CASE Ch OF
^H : IF Len > 0 THEN
BEGIN
DEC(Len);
St[0] := CHR(Len);
IF Echo THEN I_ComWrite(ComPort,#8#32#8);
END
ELSE
ComWriteChW(ComPort,^G);
^M : BEGIN
Done := TRUE;
IF Echo THEN I_ComWrite(ComPort,#13#10);
END;
^X : BEGIN
St := '';
IF Len = 0 THEN ComWriteCh(ComPort,^G);
IF Echo THEN
FOR X := 1 TO Len DO
I_ComWrite(ComPort,#8#32#8);
END;
#32..#127 : IF Len < Size THEN
BEGIN
INC(Len);
St[Len] := Ch;
St[0] := CHR(Len);
IF Echo THEN ComWriteChW(ComPort,Ch);
END
ELSE
IF Echo THEN ComWriteChW(ComPort,^G);
ELSE
IF Echo THEN ComWriteChW(ComPort,^G)
END;
UNTIL Done;
END;
{****************************************************************************}
{* *}
{* Function ComExist(ComPort:Byte) : Boolean *}
{* *}
{* ComPort:Byte -> Port # to use (1 - C_MaxCom) *}
{* Returns FALSE if out of range *}
{* Returns TRUE if hardware for selected port is detected & tests OK *}
{* *}
{* Function ComExist performs a high-speed short loopback test on the *}
{* selected port to determine if it indeed exists. Use this function *}
{* before attempts to OPEN a port for I/O (although this function is *}
{* called by OpenCom to prevent such an occurance). *}
{* NOTE! Although pains are taken to preserve the 8250 state before the *}
{* port test takes place, it is nonetheless recommended that this function *}
{* NOT be called while a port is actually OPEN. Doing so may cause the *}
{* port to behave erratically. *}
{* *}
{****************************************************************************}
FUNCTION ComExist(ComPort : BYTE) : BOOLEAN;
CONST
TestByte1 : BYTE = $0F;
TestByte2 : BYTE = $F1;
VAR
P : WORD;
M,L,B1,B2 : BYTE;
BEGIN
ComExist := FALSE;
IF (ComPort < 1) OR (ComPort > C_MaxPort) THEN EXIT;
P := C_PortAddr[ComPort];
M := Port[P + C_MCR]; { Save MCR }
L := Port[P + C_LCR]; { Save LCR }
Port[P + C_MCR] := $10; { Enable loopback mode }
Port[P + C_LCR] := $80; { Enable divisor latch mode }
B1 := Port[P]; { Save current baud rate }
B2 := Port[P + 1];
Port[P] := 4; { Set baud rate to 28000 }
Port[P + 1] := 0;
Port[P + C_LCR] := $03; { Transmit mode 28000:8N1 }
Port[P] := TestByte1; { Test byte #1 }
DELAY(20); { Wait a bit for loopback }
IF Port[P] <> TestByte1 THEN EXIT; { Exit w/error if not echoed }
Port[P] := TestByte2; { Test byte #2 }
DELAY(20); { Wait a bit for loopback }
IF Port[P] <> TestByte2 THEN EXIT; { Exit w/error if not echoed }
ComExist := TRUE; { Test passed: Port exists }
Port[P + C_LCR] := $80; { Restore baud rate }
Port[P] := B1;
Port[P + 1] := B2;
Port[P + C_LCR] := L; { Restore parameters }
Port[P + C_MCR] := M; { Restore control lines }
END;
{****************************************************************************}
{* *}
{* Function ComTrueBaud(Baud:Longint) : Real *}
{* *}
{* Baud:Longint -> User baud rate to test. *}
{* Should be between C_MinBaud and C_MaxBaud. *}
{* Returns the actual baud rate based on the accuracy of the 8250 divider. *}
{* *}
{* The ASYNC11 communications package allows the programmer to select ANY *}
{* baud rate, not just those that are predefined by the BIOS or other *}
{* agency. Since the 8250 uses a divider/counter chain to generate it's *}
{* baud clock, many non-standard baud rates can be generated. However, *}
{* the binary counter/divider is not always capable of generating the *}
{* EXACT baud rate desired by a user. This function, when passed a valid *}
{* baud rate, will return the ACTUAL baud rate that will be generated. *}
{* The baud rate is based on a 8250 input clock rate of 1.73728 MHz. *}
{* *}
{****************************************************************************}
FUNCTION ComTrueBaud(Baud : LONGINT) : REAL;
VAR
X : REAL;
Y : WORD;
BEGIN
X := Baud;
IF X < C_MinBaud THEN X := C_MinBaud;
IF X > C_MaxBaud THEN X := C_MaxBaud;
ComTrueBaud := 115200 / ROUND($900 / (X / 50));
END;
{****************************************************************************}
{* *}
{* Procedure ComParams(ComPort:Byte; Baud:Longint; *}
{* WordSize:Byte; Parity:Char; StopBits:Byte); *}
{* *}
{* ComPort:Byte -> Port # to initialize. Must be (1 - C_MaxCom) *}
{* Procedure aborted if port # invalid or unopened. *}
{* Baud:Longint -> Desired baud rate. Should be (C_MinBaud - C_MaxBaud)*}
{* C_MinBaud or C_MaxBaud used if out of range. *}
{* WordSize:Byte -> Word size, in bits. Must be 5 - 8 bits. *}
{* 8-bit word used if out of range. *}
{* Parity:Char -> Parity classification. *}
{* May be N)one, E)ven, O)dd, M)ark or S)pace. *}
{* N)one selected if classification unknown. *}
{* StopBits:Byte -> # of stop bits to pad character with. Range (1-2) *}
{* 1 stop bit used if out of range. *}
{* *}
{* ComParams is used to configure an OPEN'ed port for the desired comm- *}
{* unications parameters, namely baud rate, word size, parity form and *}
{* # of stop bits. A call to this procedure will set up the port approp- *}
{* riately, as well as assert the DTR, RTS and OUT2 control lines and *}
{* clear all buffers. *}
{* *}
{****************************************************************************}
PROCEDURE ComParams(ComPort : BYTE; Baud : LONGINT; WordSize : BYTE; Parity : CHAR; StopBits : BYTE);
CONST
C_Stopbit1 = $00; { Bit masks for parity, stopbits }
C_Stopbit2 = $04;
C_NoParity = $00;
C_OddParity = $08;
C_EvenParity = $18;
C_MarkParity = $28;
C_SpaceParity = $38;
VAR
X : REAL;
Y,P : WORD;
DivMSB,DivLSB,BaudB : BYTE;
WS,SB,PTY : BYTE;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
INLINE($FA);
P := C_PortAddr[ComPort];
{ Calculate baud rate divisors }
X := Baud;
IF X < C_MinBaud THEN X := C_MinBaud;
IF X > C_MaxBaud THEN X := C_MaxBaud;
Y := ROUND($900 / (X / 50));
DivMSB := HI(Y);
DivLSB := LO(Y);
{ Determine parity mask }
{ Default if unknown: No parity }
CASE UPCASE(Parity) OF
'N' : PTY := C_NoParity;
'E' : PTY := C_EvenParity;
'O' : PTY := C_OddParity;
'M' : PTY := C_MarkParity;
'S' : PTY := C_SpaceParity;
ELSE
PTY := C_NoParity;
END;
{ Determine stop-bit mask }
{ Default if out of range: 1 Stop bit }
CASE StopBits OF
1 : SB := C_StopBit1;
2 : SB := C_StopBit2;
ELSE
SB := C_StopBit1;
END;
{ Determine word-size mask }
{ Default if out of range: 8 bit word size }
IF (WordSize >= 5) AND (WordSize <= 8) THEN
WS := WordSize - 5
ELSE
WS := 3;
{ Initialize line-control register }
Y := Port[P] + Port[P + C_LSR];
Port[P + C_LCR] := WS + SB + PTY;
{ Initialize baud rate divisor latches }
Port[P + C_LCR] := Port[P + C_LCR] OR $80;
Port[P] := DivLSB;
Port[P + 1] := DivMSB;
Port[P + C_LCR] := Port[P + C_LCR] AND $7F;
X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
{ Assert RS323 control lines (DTR,RTS,OUT2) & exit }
Port[P + C_MCR] := $0B;
ClearCom(ComPort,'B');
{begin new stuff}
Port[$20] := $20;
IF C_CascadeOK[comport] THEN
Port[$A0] := $20;
{end new stuff}
INLINE($FB);
END;
{****************************************************************************}
{* *}
{* Function OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word):Boolean *}
{* *}
{* ComPort:Byte -> Port # to OPEN (1 - C_MaxCom) *}
{* Request will fail if out of range or port OPEN *}
{* InBufferSize:Word -> Requested size of input (receive) buffer *}
{* OutBufferSize:Word -> Requested size of output (transmit) buffer *}
{* Returns success/fail status of OPEN request (TRUE if OPEN successful) *}
{* *}
{* OpenCom must be called before any activity (other than existence check, *}
{* see the ComExist function) takes place. OpenCom initializes the *}
{* interrupt drivers and serial communications hardware for the selected *}
{* port, preparing it for I/O. Memory for buffers is allocated on the *}
{* Pascal "heap", thus freeing data-segment memory for larger more data- *}
{* intensive programs. Once a port has been OPENed, a call to ComParams *}
{* should be made to set up communications parameters (baud rate, parity *}
{* and the like). Once this is done, I/O can take place on the port. *}
{* OpenCom will return a TRUE value if the opening procedure was success- *}
{* ful, or FALSE if it is not. *}
{* *}
{****************************************************************************}
FUNCTION OpenCom(ComPort : BYTE; InBufferSize,OutBufferSize : WORD) : BOOLEAN;
VAR
TempVec : POINTER;
P : WORD;
IntLn,Cas_IntLn,X : BYTE;
BEGIN
{ Ensure that port was not previously open }
OpenCom := FALSE;
C_CascadeOK[comport] := FALSE;
C_cascade[comport] := 0;
IF (ComPort < 1) OR (ComPort > C_MaxPort) OR C_PortOpen[ComPort] THEN EXIT;
C_msrport := c_portaddr[comport] + c_msr;
{ Clear any pending activity from 8250 interrupt queue }
INLINE($FA);
{ Set up interrupt vectors & 8259 PIC }
P := C_PortAddr[ComPort];
c_oldier[comport] := port[P + c_ier];
c_oldmcr[comport] := port[P + c_mcr];
Port[P + C_IER] := $0D;
X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
IntLn := C_PortInt[ComPort];
IF IntLn > 7 THEN C_CascadeOK[comport] := TRUE;
IF C_CascadeOK[comport] THEN
BEGIN
Cas_IntLn := IntLn - 8;
GETINTVEC($70 + Cas_IntLn,TempVec);
IF C_OldINTVec[IntLn] <> TempVec THEN
BEGIN
C_Cascade[comport] := 1;
C_OldINTVec[IntLn] := TempVec;
SETINTVEC($70 + Cas_IntLn,@Int_Handler);
Port[$21] := Port[$21] AND (($01 SHL $02) XOR $FF);
X := Port[$21];
Port[$A1] := Port[$A1] AND (($01 SHL Cas_IntLn) XOR $FF);
X := Port[$A1];
END;
END
ELSE
BEGIN
GETINTVEC(8 + IntLn,TempVec);
IF C_OldINTVec[IntLn] <> TempVec THEN
BEGIN
C_OldINTVec[IntLn] := TempVec;
SETINTVEC(8 + IntLn,@Int_Handler);
Port[$21] := Port[$21] AND (($01 SHL IntLn) XOR $FF);
X := Port[$21];
END;
END;
Port[P + C_MCR] := $0B;
{new stuff (enable FIFO's, if found)}
IF C_FifoOK[comport] THEN BEGIN
c_oldfcr[comport] := port[c_portaddr[comport] + 2];
{v- enable FIFO's, clear both FIFO's, and set recieve trigger level to 14}
port[c_portaddr[comport] + 2] := $C7;
{v- check to see if FIFO's are enabled. if not, they don't exist}
x := (port[c_portaddr[comport] + C_IIR] AND $40) SHR 6; {get bit 6}
c_fifoOK[comport] := (x = 1);
END;
{end new}
{ Allocate memory for I/O buffers }
C_InSize[ComPort] := InBufferSize;
C_OutSize[ComPort] := OutBufferSize;
GETMEM(C_InBufPtr[ComPort],InBufferSize);
GETMEM(C_OutBufPtr[ComPort],OutBufferSize);
{ Set up default parameters for port }
C_RTSOn[ComPort] := InBufferSize - 2;
C_RTSOff[ComPort] := InBufferSize - 1;
C_StartChar[ComPort] := ^Q;
C_StopChar[ComPort] := ^S;
C_PortOpen[ComPort] := TRUE;
OpenCom := TRUE;
INLINE($FB);
END;
{****************************************************************************}
{* *}
{* Procedure CloseCom(ComPort:Byte) *}
{* *}
{* ComPort:Byte -> Port # to close *}
{* Request ignored if port closed or out of range. *}
{* *}
{* CloseCom will un-link the interrupt drivers for a port, deallocate it's *}
{* buffers and drop the DTR and RTS signal lines for a port opened with *}
{* the OpenCom function. It should be called before exiting your program *}
{* to ensure that the port is properly shut down. *}
{* NOTE: CloseCom shuts down a communications channel IMMEDIATELY, *}
{* even if there is data present in the input or output buffers. *}
{* Therefore, you may wish to call the ComWaitForClear procedure *}
{* before closing the ports. *}
{* *}
{****************************************************************************}
PROCEDURE CloseCom(ComPort : BYTE);
VAR
ClosePort : BOOLEAN;
P,IntLn,Cas_IntLn,X : WORD;
BEGIN
IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
{ Drop RS232 control lines (DTR,RTS,OUT2) and reset 8250 interrupt mode }
INLINE($FA);
P := C_PortAddr[ComPort];
Port[P + C_IER] := c_oldier[comport];
C_PortOpen[ComPort] := FALSE;
{ Reset INT vectors & 8259 PIC if all COMs on selected INT are closed }
IntLn := C_PortInt[ComPort];
ClosePort := TRUE;
FOR X := 1 TO C_MaxCom DO
IF C_PortOpen[X] AND (C_PortInt[X] = IntLn) THEN ClosePort := FALSE;
IF ClosePort THEN
IF C_CascadeOk[comport] THEN
BEGIN
Cas_IntLn := IntLn - 8;
Port[$21] := Port[$21] OR ($01 SHR $02);
X := Port[$21];
Port[$A1] := Port[$A1] OR ($01 SHR Cas_IntLn);
X := Port[$A1];
SETINTVEC($70 + Cas_IntLn,C_OldINTVec[IntLn]);
END
ELSE
BEGIN
Port[$21] := Port[$21] OR ($01 SHR IntLn);
X := Port[$21];
SETINTVEC(8 + IntLn,C_OldINTVec[IntLn]);
END;
X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
{new stuff}
IF C_FifoOK[comport] THEN port[c_portaddr[comport] + 2] := c_oldfcr[comport];
{end new}
{ Deallocate buffers }
FREEMEM(C_InBufPtr[ComPort],C_InSize[ComPort]);
FREEMEM(C_OutBufPtr[ComPort],C_OutSize[ComPort]);
INLINE($FB);
END;
{****************************************************************************}
{* *}
{* Procedure CloseAllComs *}
{* *}
{* CloseAllComs will CLOSE all currently OPENed ports. See the CloseCom *}
{* procedure description for more details. *}
{* *}
{****************************************************************************}
PROCEDURE CloseAllComs;
VAR
X : BYTE;
BEGIN
FOR X := 1 TO C_MaxCom DO IF C_PortOpen[X] THEN CloseCom(X);
END;
{****************************************************************************}
{* *}
{* UNIT Initialization Code *}
{* *}
{****************************************************************************}
BEGIN
FOR x := 1 TO C_MaxPort DO
BEGIN
C_PortOpen[x] := FALSE;
C_InBufPtr[x] := NIL;
C_OutBufPtr[x] := NIL;
C_OldIntVec[x] := NIL;
C_InHead[x] := 0;
C_OutHead[x] := 0;
C_InTail[x] := 0;
C_OutTail[x] := 0;
C_InSize[x] := 0;
C_OutSize[x] := 0;
C_RTSOn[x] := $FFFF;
C_RTSOff[x] := $FFFF;
C_StartChar[x] := ^Q;
C_StopChar[x] := ^S;
C_Status[x] := $05;
C_Ctrl[x] := 0;
C_XL3Ptr[x] := 0;
C_buffull[x] := 0;
C_cascade[x] := 0;
C_cascadeok[x] := FALSE;
c_oldier[x] := 0;
c_oldmcr[x] := 0;
c_oldfcr[x] := 0;
c_FifoOK[x] := FALSE;
END;
END.